use std::{path::Path, ffi::CString};

use ash::vk::{self, Offset2D};

use crate::{vulkan::{VkContext, vk_utils::{utils_info, utils_pipeline}, vk_struct::{VkSwapchain, VkPipelineGenerator, VkPipeline, VkImage, VkTexture, VkDescriptorSet, VkWriteDescriptorSetGenerator}, vk_context}, VK_CHECK_UNSAFE, VK_LOGP, VK_LOGD, system::{render::RenderSystem, MAX_FRAMES_IN_FLIGHT}};

// use super::RenderPassTrait;

pub struct PostRenderPassCreateInfo<'a> {
    pub swapchain           : &'a VkSwapchain,
    pub input_texture       : &'a VkTexture
}

pub struct PostRenderPass {
    pub render_pass         : vk::RenderPass,
    pub framebuffers        : Vec<vk::Framebuffer>,
    pub pipeline            : VkPipeline,
    pub descriptor_sets     : Vec<vk::DescriptorSet>
}

impl PostRenderPass {
    pub fn new(vk_context: &VkContext, create_info: PostRenderPassCreateInfo) -> Self {
        let swapchain_extent    = create_info.swapchain.get_extent();

        let render_pass         = Self::setup_vk_render_pass(vk_context, &create_info.swapchain.used_format.format);
        let framebuffers        = Self::setup_framebuffers(vk_context, create_info.swapchain, &render_pass);

        let pipeline            = Self::setup_vk_pipeline(vk_context, &render_pass, &swapchain_extent);
        let descriptor_sets     = Self::setup_descriptor_set(vk_context, &pipeline, create_info.input_texture);

        Self {
            render_pass,
            framebuffers,
            pipeline,
            descriptor_sets
        }
    }

    fn setup_vk_render_pass(vk_context: &VkContext, color_format: &vk::Format) -> vk::RenderPass {
        let mut color_attachment = utils_info::get_attachment_description();
        color_attachment.format         = *color_format;
        color_attachment.load_op        = vk::AttachmentLoadOp::CLEAR;
        color_attachment.store_op       = vk::AttachmentStoreOp::STORE;
        color_attachment.final_layout   = vk::ImageLayout::PRESENT_SRC_KHR;
        // attachment本身是不分color和depth的
        // 真正区分的是在Reference的layout，手动区分
        let attachments = [color_attachment];
        // 这里其实才把上面的attachment做了Color和depth的分配
        // Color可以有很多，Depth只有一个
        let color_attachment_ref = [vk::AttachmentReference {attachment: 0, layout: vk::ImageLayout::COLOR_ATTACHMENT_OPTIMAL}]; 
        VK_LOGD!("为什么这里用PRESENT_SRC_KHR会报错VUID-VkAttachmentReference2-layout-03077");
        let depth_attachment_ref = [vk::AttachmentReference {attachment: 1, layout: vk::ImageLayout::DEPTH_STENCIL_ATTACHMENT_OPTIMAL}];
        // 将Attachment Reference写到subpass description中
        // 可以知道如果有多个subpass，就可以将不同的attachment链上去
        let mut subpass_description = utils_info::get_subpass_description();
        subpass_description.color_attachment_count      = color_attachment_ref.len() as u32;
        subpass_description.p_color_attachments         = color_attachment_ref.as_ptr();
        // subpass_description.p_depth_stencil_attachment  = depth_attachment_ref.as_ptr();
        let subpass_description = [subpass_description];
        // 这里同步很重要，还得看一会，同步的粒度太多了
        let dependency = [vk::SubpassDependency {
            src_subpass                     : vk::SUBPASS_EXTERNAL,
            dst_subpass                     : 0,
            src_stage_mask                  : vk::PipelineStageFlags::BOTTOM_OF_PIPE,
            dst_stage_mask                  : vk::PipelineStageFlags::COLOR_ATTACHMENT_OUTPUT,
            src_access_mask                 : vk::AccessFlags::MEMORY_READ,
            dst_access_mask                 : vk::AccessFlags::COLOR_ATTACHMENT_WRITE,// | vk::AccessFlags::DEPTH_STENCIL_ATTACHMENT_WRITE,
            dependency_flags                : vk::DependencyFlags::BY_REGION,
        }];

        let mut render_pass_ci = utils_info::get_render_pass_ci();
        render_pass_ci.subpass_count        = subpass_description.len() as u32;
        render_pass_ci.p_subpasses          = subpass_description.as_ptr();
        render_pass_ci.attachment_count     = attachments.len() as u32;
        render_pass_ci.p_attachments        = attachments.as_ptr();
        render_pass_ci.dependency_count     = dependency.len() as u32;
        render_pass_ci.p_dependencies       = dependency.as_ptr();
        match VK_CHECK_UNSAFE!(vk_context.vk_device.create_render_pass(&render_pass_ci, None)) {
            Some(inner_value)   => inner_value,
            None                => VK_LOGP!("Failed to create_render_pass")
        }
    }

    fn setup_vk_pipeline(vk_context: &VkContext, render_pass: &vk::RenderPass, swapchain_extent: &vk::Extent2D) -> VkPipeline {
        enum DescriptorSetLayoutType {
            INPUTIMAGE,
            COUNER
        }

        let mut pipeline_generator = VkPipelineGenerator::new(DescriptorSetLayoutType::COUNER as usize);
        // Configure pipeline generator
        // Configure shader
        let temp = CString::new("main").unwrap();
        let entry_name = temp.as_ptr();
        pipeline_generator.add_shader(vk_context, &Path::new("./vulkan-rt-test/src/shaders/spv/post.vert.spv"), vk::ShaderStageFlags::VERTEX  , entry_name);
        pipeline_generator.add_shader(vk_context, &Path::new("./vulkan-rt-test/src/shaders/spv/post.frag.spv"), vk::ShaderStageFlags::FRAGMENT, entry_name);
        // Configure dynamic state
        let dynamic_states  = vec![vk::DynamicState::VIEWPORT, vk::DynamicState::SCISSOR];
        pipeline_generator.state.dynamic_state.dynamic_state_count = dynamic_states.len() as u32;
        pipeline_generator.state.dynamic_state.p_dynamic_states    = dynamic_states.as_ptr();
        // Configure viewport state
        let viewports       = [utils_pipeline::get_viewport(swapchain_extent)];
        let scissors        = [utils_pipeline::get_scissor(swapchain_extent)];
        pipeline_generator.state.viewport_state.viewport_count     = viewports.len() as u32;
        pipeline_generator.state.viewport_state.p_viewports        = viewports.as_ptr();
        pipeline_generator.state.viewport_state.scissor_count      = scissors.len() as u32;
        pipeline_generator.state.viewport_state.p_scissors         = scissors.as_ptr();
        // Configure color blend state
        let pipeline_color_blend_attachment_state = [utils_info::get_pipeline_color_blend_attachment_state()];
        pipeline_generator.state.color_blend_state.attachment_count   = pipeline_color_blend_attachment_state.len() as u32;
        pipeline_generator.state.color_blend_state.p_attachments      = pipeline_color_blend_attachment_state.as_ptr();
        // Configure Layout
        pipeline_generator.add_set_binding(DescriptorSetLayoutType::INPUTIMAGE as usize, 0, vk::DescriptorType::COMBINED_IMAGE_SAMPLER, 1, vk::ShaderStageFlags::FRAGMENT, std::ptr::null());
        // Do gen
        pipeline_generator.generate(&vk_context, render_pass, 0)
    }

    fn setup_descriptor_set(vk_context: &VkContext, pipeline: &VkPipeline, input_texture: &VkTexture) -> Vec<vk::DescriptorSet> {
        // 根据输入的Layout创建一定数量的Desceriptor Set
        let mut descriptor_set_ai = utils_info::get_descriptor_set_allocate_info(); 
        descriptor_set_ai.descriptor_pool           = vk_context.vk_descriptor_pool;
        descriptor_set_ai.descriptor_set_count      = 1;
        descriptor_set_ai.p_set_layouts             = pipeline.descriptor_set_layouts.as_ptr();

        // 将资源的Handler绑定到Descriptor Set上
        // 这里因为Descriptor Set只能一个一个创建
        // 这里是否也可以设计成Generator的形式
        let mut output_descriptor_sets = vec![];

        for _ in 0..MAX_FRAMES_IN_FLIGHT as usize {
            // 创建Set
            let descriptor_sets = match VK_CHECK_UNSAFE!(vk_context.vk_device.allocate_descriptor_sets(&descriptor_set_ai)) {
                Some(inner_value)   => inner_value,
                None                => VK_LOGP!("Failed to allocate_descriptor_sets")
            };
            // 处理对应需要写入的Binding位置
            let mut write_descriptor_generator = VkWriteDescriptorSetGenerator::new();
            write_descriptor_generator.add_image_info(input_texture, &descriptor_sets[0], 0, &input_texture.description, false);
            let write_descriptor_sets = write_descriptor_generator.generate();
            // 向Descriptor Set中写入对应的Handler
            unsafe{ vk_context.vk_device.update_descriptor_sets(write_descriptor_sets, &[]) }

            output_descriptor_sets.push(descriptor_sets[0]);
        }

        output_descriptor_sets
    }

    fn setup_framebuffers(vk_context: &VkContext, swapchain: &VkSwapchain, render_pass: &vk::RenderPass) -> Vec<vk::Framebuffer> {
        let mut framebuffers = vec![];
        let extent = swapchain.get_extent();
        for image_view in &swapchain.image_views {
            framebuffers.push(vk_context.create_framebuffer(extent.width, extent.height, &render_pass, &vec![*image_view]));
        }
        framebuffers
    }

    pub fn on_window_size_changed(&mut self, vk_context: &VkContext, create_info: PostRenderPassCreateInfo) {
        vk_context.destory_framebuffers(&self.framebuffers);

        for index in 0..MAX_FRAMES_IN_FLIGHT as usize {
            // 处理对应需要写入的Binding位置
            let mut write_descriptor_generator = VkWriteDescriptorSetGenerator::new();
            write_descriptor_generator.add_image_info(create_info.input_texture, &self.descriptor_sets[index], 0, &create_info.input_texture.description, false);
            let write_descriptor_sets = write_descriptor_generator.generate();
            // 向Descriptor Set中写入对应的Handler
            unsafe{ vk_context.vk_device.update_descriptor_sets(write_descriptor_sets, &[]) }
        }

        self.framebuffers = Self::setup_framebuffers(vk_context, create_info.swapchain, &self.render_pass);
    }
}